package mynet

import (
	"context"
	"fmt"
	"log"
	"my-gameserver-go/core/eventbus"
	"my-gameserver-go/core/mynet/conn"
	mynet_handler "my-gameserver-go/core/mynet/handler"
	"my-gameserver-go/core/mynet/handler/abs"
	"my-gameserver-go/logic/consts"
	"my-gameserver-go/logic/login"
	playerHandler "my-gameserver-go/logic/player/handler"
	player_mananger "my-gameserver-go/logic/player/manager"
	"time"
)

type NetManager struct {
	messageHandlerPool map[uint32]abs.ProtoMessageHandler //msgHandler pool(消息池)
}

var InsNetManager *NetManager

func init() {
	InsNetManager = &NetManager{
		messageHandlerPool: make(map[uint32]abs.ProtoMessageHandler),
	}
}

func (netManager NetManager) Start() {
	netManager.RegisterMsgHandler()
	netManager.StartPlayerRoutinePool()
}

//RegisterMsgHandler 注册msgHandler的type，在 DispatchMessage 中使用反射获取实例
func (netManager *NetManager) RegisterMsgHandler() {
	netManager.messageHandlerPool[1101] = playerHandler.MReqPlayerHeartHandler{}
	netManager.messageHandlerPool[100] = login.MReqLoginHandler{}

}

//StartConn 启动连接，让当前连接开始工作
func (netManager *NetManager) StartConn(c *conn.GameConnection) {
	c.Ctx, c.Cancel = context.WithCancel(context.Background())
	eventbus.Publish(consts.CONN_ACTIVE, c)
	//1 开启用户从客户端读取数据流程的Goroutine
	go netManager.StartReader(c)
	//2 开启用于写回客户端数据流程的Goroutine
	go netManager.StartWriter(c)
	//开启messageDispatcher Goroutine
	go netManager.StartMessageDispatcher(c)
	select {
	case <-c.Ctx.Done():
		netManager.finalizer(c)
		return
	}
}

//StartReader 读消息Goroutine，用于从客户端中读取数据
func (netManager *NetManager) StartReader(c *conn.GameConnection) {
	fmt.Println("[Reader Goroutine is running]")
	defer fmt.Println(c.Conn.RemoteAddr().String(), "[conn Reader exit!]")
	defer c.Cancel()
	// 创建拆包解包的对象
	for {
		select {
		case <-c.Ctx.Done():
			return
		default:
			if msg, ok := c.GetCoder().Decode(c.Conn); ok {
				//处理message
				// 发送超时
				idleTimeout := time.NewTimer(5 * time.Millisecond)
				select {
				case <-idleTimeout.C:
					fmt.Println("send buff msg timeout")
				case c.MsgDispatchChan <- msg:
					fmt.Println("c.MsgDispatchChan write success")
				}
			} else {
				return
			}
		}
	}
}

//StartWriter 写消息Goroutine， 用户将数据发送给客户端
func (netManager *NetManager) StartWriter(c *conn.GameConnection) {
	fmt.Println("[Writer Goroutine is running]")
	defer fmt.Println(c.Conn.RemoteAddr().String(), "[conn Writer exit!]")
	for {
		select {
		case rmsg, ok := <-c.MsgSendChan:
			if ok {
				//有数据要写给客户端
				//decode
				byteData, err := c.GetCoder().Codec(rmsg)
				if err != nil {
					log.Println("msg Codec err,msgId:", rmsg.MsgId)
					return
				}
				if _, err := c.Conn.Write(byteData); err != nil {
					fmt.Println("Send Buff Data error:, ", err, " Conn Writer exit")
					return
				}
				callBack := rmsg.Callback
				//执行回调
				if callBack != nil {
					callBack()
				}
			} else {
				fmt.Println("msgBuffChan is Closed")
				break
			}
		case <-c.Ctx.Done():
			return
		}
	}
}

//StartPlayerRoutinePool 启动玩家goroutinePool
func (netManager *NetManager) StartPlayerRoutinePool() {
	//遍历需要启动worker的数量，依此启动
	for i := 0; i < consts.PlayerRoutineNum; i++ {
		pChan := make(chan mynet_handler.BaseHandler, consts.MaxBufferSize)
		player_mananger.InsPlayerManager.PlayerRoutinePool[i] = pChan
		//启动玩家goroutine
		k := i
		go func(chan mynet_handler.BaseHandler) {
			fmt.Println("Start PlayerRoutine :", k+1)
			//不断的等待队列中的消息
			for {
				select {
				case msgHandler := <-pChan:
					msgHandler.Action()
				}
			}
		}(pChan)
	}
}

func (netManager *NetManager) finalizer(c *conn.GameConnection) {
	c.Lock()
	defer c.Unlock()
	fmt.Println("Conn Stop()...addr = ", c.Conn.RemoteAddr().String())
	// 关闭socket链接
	err := c.Conn.Close()
	c.Isclosed = true
	if err != nil {
		fmt.Println("Conn Stop() err :", err)
		return
	}
	eventbus.Publish(consts.CONN_CLOSE, c)
	//关闭该链接全部管道
	close(c.MsgDispatchChan)
	close(c.MsgSendChan)
}

//StartMessageDispatcher MessageDispatcher goroutine(单router)
func (netManager *NetManager) StartMessageDispatcher(c *conn.GameConnection) {
	fmt.Println("[MessageDispatcher Goroutine is running]")
	for {
		select {
		case msg, ok := <-c.MsgDispatchChan:
			if ok {
				msgHandler := netManager.messageHandlerPool[msg.ID]
				genericProtoHandler := abs.GenericProtoHandler{
					Conn:                c,
					Data:                msg.Data,
					ProtoMessageHandler: msgHandler,
				}
				if msgHandler == nil {
					fmt.Println("can not find msgHandler msgId:", msg.ID)
					return
				}
				if msg.ID == consts.LoginMessageId {
					//开始登陆
					//TODO 登陆这里直接开的go routine
					go func() {
						genericProtoHandler.Action()
					}()
				} else {
					//登陆之后的走playerRoutine
					player, ok := player_mananger.InsPlayerManager.GetPlayerByConn(c.Conn)
					if !ok {
						fmt.Println("can not find player by conn!")
						return
					}
					player_mananger.InsPlayerManager.ProtoHandlerSend(player.RoutineChanIndex, genericProtoHandler)
				}
			} else {
				fmt.Println("MsgDispatchChan is Closed")
				break
			}

		case <-c.Ctx.Done():
			return
		}
	}
}
